﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using PostSharp.Aspects;
using SecurityFoundation;
using SecurityFoundation.Entities;

namespace SecurityAgent
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    [Serializable]
    public class RequireAdminAccess : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs args)
        {
            string applicationKey = (string) args.Arguments[0];
            string operatorToken = (string) args.Arguments[1];

            if (String.IsNullOrEmpty(operatorToken))
                throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = args.Method.DeclaringType.Name, Operation = args.Method.Name }, new FaultReason("Unauthorized access attempt recorded"));

            RoleProviderService roleService = new RoleProviderService();

            if (!roleService.IsAuthorizedAdmin(applicationKey, operatorToken))
            {
                throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = args.Method.DeclaringType.Name, Operation = args.Method.Name }, new FaultReason("Unauthorized access attempt recorded"));
            }
        }
    }

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    [Serializable]
    public class RequireAdminOrSelfAccess : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs args)
        {
            string applicationKey = (string)args.Arguments[0];
            string operatorToken = (string)args.Arguments[1];
            string userName = (string)args.Arguments[2];

            if (String.IsNullOrEmpty(operatorToken))
                throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = args.Method.DeclaringType.Name, Operation = args.Method.Name });

            RoleProviderService roleService = new RoleProviderService();

            if (!roleService.IsAuthorizedAdmin(applicationKey, operatorToken))
            {
                SecurityToken op = Repository.GetToken(new Guid(operatorToken.ToString()));
           
                if(op == null || op.UserName != userName)
                    throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = args.Method.DeclaringType.Name, Operation = args.Method.Name });
            }
        }
    }

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple=true)]
    [Serializable]
    public class SecurityExceptionHandler : OnExceptionAspect
    {
        public override void OnException(MethodExecutionArgs args)
        {
            if (args.Exception is FaultException)
            {
                args.FlowBehavior = FlowBehavior.RethrowException;
            }
            else
            {
                string arg1 = string.Empty;
                string arg2 = string.Empty;

                if (args.Arguments.Count > 1) arg1 = args.Arguments[1].ToString();
                if (args.Arguments.Count > 2) arg2 = args.Arguments[2].ToString();

                SecurityFault fault = new SecurityFault { Application = args.Arguments[0].ToString(), Message = args.Exception.Message, Argument1 = arg1, Argument2 = arg2 };
                throw new FaultException<SecurityFault>(fault, new FaultReason("Error in processing security request: " + args.Exception.Message));
                //base.OnException(args);
            }
        }
    }

}
